﻿using System.Runtime.InteropServices;
using static shbxdv.Ezviz.OpenNetStream;

namespace shbxdv.Ezviz
{
    /// <summary>
    /// 会话对象
    /// </summary>
    public class OpenSDKSession : IDisposable
    {
        /// <summary>
        /// 消息处理器
        /// </summary>
        internal static readonly OpenSDK_MsgHandler MessageHandler;

        /// <summary>
        /// 消息接收事件
        /// </summary>
        public event EventHandler<SessionMessageEventArgs> MessageReceived;

        /// <summary>
        /// 内部维持的会话对象
        /// </summary>
        internal IntPtr Session { get; set; }

        public bool IsDisposed => this.Session == IntPtr.Zero;

        /// <summary>
        /// 异步模式
        /// </summary>
        public bool Sync
        {
            get;
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="sync">是否支持异步（默认支持）</param>
        internal OpenSDKSession(bool sync=true)
        {
            this.Sync = sync;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        static OpenSDKSession()
        {
            OpenSDKSession.MessageHandler = new OpenSDK_MsgHandler(OpenSDKSession.HandleMessage);
        }

        /// <summary>
        /// 设置数据回调
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="userData"></param>
        /// <returns></returns>
        public int SetDataCallBack(OpenSDK_DataCallBack callback, IntPtr userData)
        {
            return OpenNetStream.OpenSDK_SetDataCallBack(this.Session, callback, userData);

        }
        /// <summary>
        /// 播放视频
        /// </summary>
        /// <param name="hwnd">播放窗口句柄</param>
        /// <param name="devSerial">设备序列号</param>
        /// <param name="channelNo">视频质量，输入范围在1-3之间</param>
        /// <param name="safeKey">视频加密密钥，默认为设备验证码，无设备验证码则为ABCDEF</param>
        /// <returns>0表示成功，非0表示失败</returns>
        public int StartRealPlay(IntPtr hwnd, string devSerial, int channelNo, string safeKey)
        {
            return OpenNetStream.OpenSDK_StartRealPlayEx(this.Session, hwnd, devSerial, channelNo, safeKey);
        }

        /// <summary>
        /// 停止预览
        /// </summary>
        /// <returns></returns>
        public int StopRealPlay()
        {
            return OpenNetStream.OpenSDK_StopRealPlayEx(this.Session);
        }
        /// <summary>
        /// 设置或者切换清晰度
        /// </summary>
        /// <param name="subSerial">设备序列号</param>
        /// <param name="iChannelNo">设备通道号</param>
        /// <param name="iVideoLevel">视频质量，输入范围在0-3之间, 0-流畅; 1-均衡; 2-高清; 3-超清<see cref="VideoLevel"/></param>
        /// <returns></returns>
        public int SetVideoLevel(string subSerial, int iChannelNo, int iVideoLevel)
        {
            return OpenNetStream.OpenSDK_SetVideoLevel(subSerial, iChannelNo, iVideoLevel);
        }

        public int StartSearch(string devSerial, int channelNo, string startTime, string stopTime)
        {
             return OpenNetStream.OpenSDK_StartSearchEx(this.Session, devSerial, channelNo, startTime, stopTime);

        }
        /// <summary>
        /// 回放
        /// </summary>
        /// <param name="playWnd">播放窗口句柄</param>
        /// <param name="devSerial">监控视频序列号</param>
        /// <param name="safeKey">视频加密密钥</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="stopTime">停止时间</param>
        /// <returns>0表示成功，非0表示失败 </returns>
        public int StartPlayBack(IntPtr playWnd, string devSerial, int channelNo, string safeKey, string startTime, string stopTime)
        {
              return OpenNetStream.OpenSDK_StartPlayBackEx(this.Session, playWnd, devSerial, channelNo, safeKey, startTime, stopTime);
        }
        /// <summary>
        /// 暂停回放
        /// </summary>
        /// <returns>0表示成功，非0表示失败 </returns>

        public int PlayBackPause()
        {
            return OpenNetStream.OpenSDK_PlayBackPause(this.Session);
        }
        /// <summary>
        /// 恢复回放
        /// </summary>
        /// <returns>0表示成功，非0表示失败 </returns>
        public int PlayBackResume()
        {
            return OpenNetStream.OpenSDK_PlayBackResume(this.Session);
        }
        /// <summary>
        /// 停止回放
        /// </summary>
        /// <returns>0表示成功，非0表示失败 </returns>
        public int StopPlayBack()
        {
            return OpenNetStream.OpenSDK_StopPlayBackEx(this.Session);
        }

        /// <summary>
        /// 打开声音
        /// </summary>
        /// <returns>0表示成功，-1表示失败</returns>
        public int OpenSound()
        {
            return OpenNetStream.OpenSDK_OpenSound(this.Session);
        }

        /// <summary>
        /// 关闭声音
        /// </summary>
        /// <returns>0表示成功，-1表示失败</returns>
        public int CloseSound()
        {
            return OpenNetStream.OpenSDK_CloseSound(this.Session);
        }

        /// <summary>
        /// 获取音量
        /// </summary>
        /// <returns> 音量大小，0-100之间</returns>
        public ushort GetVolume()
        {
            return OpenNetStream.OpenSDK_GetVolume(this.Session);
        }

        /// <summary>
        /// 设置音量
        /// </summary>
        /// <param name="volume">音量大小，0-100之间</param>
        /// <returns>0表示成功，-1表示失败<see cref="OpenSDKErrorCode"/></returns>
        public int SetVolume(ushort volume)
        {
             return OpenNetStream.OpenSDK_SetVolume(this.Session, volume);
        }
        /// <summary>
        ///截屏，StartRealPlay成功情况下使用 
        /// </summary>
        /// <param name="fileName">图片保存路径，格式为JPG，支持中文，UTF-8格式</param>
        /// <returns>0表示成功，-1表示失败 </returns>
        public int CapturePicture(string fileName)
        {
            if (!String.IsNullOrWhiteSpace(fileName))
            {
                return OpenNetStream.OpenSDK_CapturePicture(this.Session, fileName);
            }
            return 1;
            
        }
        /// <summary>
        /// 开启语音对讲, 不支持多个设备同时对接
        /// </summary>
        /// <param name="devSerial">摄像头序列号</param>
        /// <param name="channelNo">通道</param>
        /// <returns></returns>
        public int StartVoiceTalk(string devSerial, int channelNo)
        {
             return OpenNetStream.OpenSDK_StartVoiceTalkEx(this.Session, devSerial, channelNo);
        }

        /// <summary>
        /// 结束语音对讲
        /// </summary>
        /// <returns>0表示成功，-1表示失败<see cref="OpenSDKErrorCode"/></returns>
        public int StopVoiceTalk()
        {
            return OpenNetStream.OpenSDK_StopVoiceTalk(this.Session);
        }

        /// <summary>
        /// 云台控制
        /// </summary>
        /// <param name="subSerial">监控点Id</param>
        /// <param name="command">云台控制命令</param>
        /// <param name="action">云台操作命令</param>
        /// <param name="speed">速度0-7之间</param>
        /// <returns>0表示成功，-1表示失败<see cref="OpenSDKErrorCode"/></returns>
        public int PTZCtrlEx( string subSerial, int iChannelNo, OpenNetStream.PTZCommand command, OpenNetStream.PTZAction action, int speed)
        {
            return OpenNetStream.OpenSDK_PTZCtrlEx(this.Session, subSerial, iChannelNo, command, action, speed);
        }


        /// <summary>
        /// 处理消息
        /// </summary>
        /// <param name="ptr"></param>
        /// <param name="msgType"></param>
        /// <param name="errorCode"></param>
        /// <param name="errorMessage"></param>
        /// <param name="userData"></param>
        private static void HandleMessage(IntPtr ptr, EZMessageType msgType, uint errorCode, string errorMessage, IntPtr userData)
        {
            int value = Marshal.ReadInt32(ptr);
            OpenSDKSession session;
            if (!EzvizOpenSDK.SESSIONS.TryGetValue(value, out session))
                return;
            if (session != null)
                //处理事件，触发事件
                session.OnMessageReceived(msgType, Convert.ToInt64(errorCode), errorMessage, userData);
        }

        /// <summary>
        /// 关闭会话
        /// </summary>
        public void Close()
        {
            if (this.IsDisposed)
                return;
            //释放会话
            int result = OpenNetStream.OpenSDK_FreeSession(this.Session);
            if (result != OpenSDKErrorCode.OK)
                return;
            EzvizOpenSDK.SESSIONS.Remove(Marshal.ReadInt32(this.Session));
            this.Session = IntPtr.Zero;
        }

        //触发消息接收事件
        private void OnMessageReceived(EZMessageType msgType, long errorCode, string errorMessage, IntPtr userData)
        {
            this.MessageReceived?.Invoke(this, new SessionMessageEventArgs(this, msgType, errorCode, errorMessage, userData));
        }

        public void Dispose()
        {
            if (this.IsDisposed)
                return;
            this.Close();
        }
    }
}